trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/maps_3.3.0.tgz'
Content type 'application/x-gzip' length 3687860 bytes (3.5 MB)
==================================================
downloaded 3.5 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpKGeCND/downloaded_packages
trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/tmap_3.3-1.tgz'
Content type 'application/x-gzip' length 3585561 bytes (3.4 MB)
==================================================
downloaded 3.4 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpKGeCND/downloaded_packages
trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/rgeos_0.5-5.tgz'
Content type 'application/x-gzip' length 8537441 bytes (8.1 MB)
==================================================
downloaded 8.1 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpKGeCND/downloaded_packages
    ADM_RATE < 0.2 ~ 'elite/highly selective',
Error: unexpected ',' in "    ADM_RATE < 0.2 ~ 'elite/highly selective',"

Simple Scattergram

First we are going to try to present this pattern for different tiers of universities (admission rate as well as debt)

This is a data table showing the breakdown of the university ranks (as I chose to rank them). I will note that from the dt alone wwe are seeing a downward trend in the ‘Median Student Loans’ column.

# Create Data Table (Summarized) for 
library('scales')

sc_dt <- sc %>% subset(DEBT_MDN !='PrivacySuppressed') %>% transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% group_by(uni_rank) %>% mutate(`Number of Universities` = n()) %>% ungroup() %>% mutate(DEBT_MDN_STUDENTS = DEBT_MDN*UGDS) %>% group_by(uni_rank) %>% mutate(`Median Student Loans` = paste('$',round(sum(DEBT_MDN_STUDENTS, na.rm=TRUE)/sum(UGDS, na.rm=TRUE),2))) %>% 
  mutate(`Min Acceptance Rate` = percent(min(ADM_RATE))) %>% mutate(`Max Acceptance Rate` = percent(max(ADM_RATE))) %>% ungroup() %>% 
  group_by(uni_rank,`Median Student Loans`,`Number of Universities`,`Min Acceptance Rate`,`Max Acceptance Rate`) %>% 
  summarize()
`summarise()` regrouping output by 'uni_rank', 'Median Student Loans', 'Number of Universities', 'Min Acceptance Rate' (override with `.groups` argument)
install.packages('DT')
Error in install.packages : Updating loaded packages
library(DT)
table <- datatable(sc_dt,style = "default",filter = 'top',  caption = 'Universities and Selectivity')
table
NA

Scattergram as Violin Plot

Showing the previous scattergram specifically as violing plots

ipeds15 <- get_education_data(level = "college-university",
    source = "ipeds",
    topic = "grad-rates-pell",
    filters = list(year = 2015))
ipeds15

Student Debt over Time

#Process the data 
sc_time <- read_csv('2010_2019_student_debt.csv') 
Error: '2010_2019_student_debt.csv' does not exist in current working directory ('/Users/ConnieXu/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd/ideas_drafts').
sum(sc_time$UGDS,na.rm=TRUE)
[1] 90801007

Below is an interactive line graph (2010-2019) which details the trends in student debt over the years.

# CPI Inflation Rates - Got Average Yearly Inflation Rate for Scaling for Student Debt 
install.packages('quantmod')
Error in install.packages : Updating loaded packages
library(quantmod)
getSymbols("CPIAUCSL", src='FRED')
[1] "CPIAUCSL"
avg.cpi <- apply.yearly(CPIAUCSL, mean)
cf <- as.data.frame(avg.cpi/as.numeric(avg.cpi['2009'])) 
cf$Year_Ending <- format(as.Date(row.names(cf), format="%Y-%m-%d"),"%Y")

# Merged for Inflation 
sc_time_df <- sc_time %>% group_by(`Year_Ending`) %>% mutate(`Average Annual Student Debt - National` = sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>% ungroup() %>% 
  dplyr::mutate(uni_rank = case_when(
    ADM_RATE < 0.2 ~ 'elite/highly selective',
    ADM_RATE < 0.3 ~ 'more selective',
    ADM_RATE < 0.5 ~ 'selective',
    ADM_RATE < 0.7 ~ 'less selective',
    TRUE ~ 'not selective')) %>%
  mutate(uni_rank = factor(uni_rank, levels=c('not selective', 'less selective', 'selective', 
                                              'more selective', 'elite/highly selective'))) %>%
  group_by(uni_rank,Year_Ending) %>% 
  mutate(`Average Annual Student Debt (by Selectivity)` = sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>% 
  ungroup() %>% 
  group_by(`Year_Ending`,`Average Annual Student Debt (by Selectivity)`,
           uni_rank,`Average Annual Student Debt - National`) %>% summarize() %>% 
  merge(cf) %>% 
  mutate(`Adjusted Average Annual Student Debt` = `Average Annual Student Debt (by Selectivity)`/
           CPIAUCSL) %>% 
  mutate(`Adjusted Average Annual Student Debt - Composite` = `Average Annual Student Debt - National`/
           CPIAUCSL)
`summarise()` regrouping output by 'Year_Ending', 'Average Annual Student Debt (by Selectivity)', 'uni_rank' (override with `.groups` argument)
sc_df <- sc_time_df %>% group_by(`Average Annual Student Debt - National`,`Adjusted Average Annual Student Debt - Composite`,Year_Ending) %>% summarize() %>% mutate(uni_rank='national average') %>% mutate(`Adjusted Average Annual Student Debt`=`Adjusted Average Annual Student Debt - Composite`) %>% dplyr::mutate(`Average Annual Student Debt (by Selectivity)` = `Average Annual Student Debt - National`) %>% merge(cf) %>% select(Year_Ending,`Average Annual Student Debt (by Selectivity)`, uni_rank, `Average Annual Student Debt - National`, CPIAUCSL, `Adjusted Average Annual Student Debt`,`Adjusted Average Annual Student Debt - Composite`)
`summarise()` regrouping output by 'Average Annual Student Debt - National', 'Adjusted Average Annual Student Debt - Composite' (override with `.groups` argument)
sc_time_df <- sc_time_df %>% rbind(sc_df) %>% mutate(uni_rank = factor(uni_rank, levels=c('national average','not selective', 'less selective', 'selective', 'more selective', 'elite/highly selective'))) %>% 
  mutate(national = ifelse(uni_rank == 'national average', 'y','n'))
sc_df
sc_time_df
brewer.pal(n=10,"PuBuGn")
n too large, allowed maximum for palette PuBuGn is 9
Returning the palette you asked for with that many colors
[1] "#FFF7FB" "#ECE2F0" "#D0D1E6" "#A6BDDB" "#67A9CF" "#3690C0" "#02818A" "#016C59" "#014636"
ShortPuBuGn <- c("#D0D1E6","#A6BDDB","#67A9CF","#3690C0","#02818A")

p <- sc_time_df %>% 
  ggplot(.,aes(x=Year_Ending,y=`Adjusted Average Annual Student Debt`, color=uni_rank, group=national)) + 
  geom_point() + geom_line(aes(linetype=national)) + 
  scale_color_manual(values=c('grey',"#D0D1E6","#A6BDDB","#67A9CF","#3690C0","#02818A"))+
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background= element_rect(fill="white")) +
  scale_x_continuous(breaks = round(seq(min(sc_time$Year_Ending), max(sc_time$Year_Ending), by = 2),1)) +
  labs(x='', y='Median Loan Amount per Student\n(thousands)**', 
       title='Student Debt Has Been Rising Over The Years',
       color='',fill='', caption='**-inflation adjusted')
ggplotly(p)
NA
NA

The following is (instead) a bar graph with fewer ‘university selectivity’ buckets.

Chloropleth showing average student debt (this is only 2019 but I have a filter at the beginning that will allow me to incorporate a slider for the year).

leaflet(states_2019) %>% addProviderTiles("CartoDB.Positron") %>%
  addPolygons(fillColor = ~pal(states_2019$`Average Student Loans`),
              color = "white",
              weight = 0.5,
              fillOpacity = 0.7,  
              highlight = highlightOptions(
                weight = 5,
                color = "#666",
                fillOpacity = 0.7,
                bringToFront = TRUE,
                ),popup=pop_pop) %>%
  leaflet::addLegend(position = "bottomleft", pal = pal, values = c(paste('$',round(min(states_2019$`Average Student Loans`))), 
                                                          paste('$',round(max(states_2019$`Average Student Loans`)))),
            title = "Average Student Loans (Per Student)") %>%   setView(-98.5795, 39.8282, zoom=3)
Some values were outside the color scale and will be treated as NAsf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'
brewer.pal(n = 8, name = "RdYlGn")
leaflet(sc_time_2019_selective) %>% addTiles('http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png') %>%
  addCircles(col = ~pal1(sc_time_2019_selective$uni_rank),
             radius = ~DEBT_MDN,
             popup = content,
             fillOpacity = 0.7) %>%
  leaflet::addLegend(position = "bottomleft",pal = pal1, values = sc_time_2019_selective$uni_rank,
            title = "Average Student Loans (Per Student)")
Assuming "long" and "lat" are longitude and latitude, respectively
Data contains 931 rows with either missing or invalid lat/lon values and will be ignored

The code chunk below has not been touched and includes Shiny code for later use.

ui <- fluidPage(
    sidebarLayout(
        sidebarPanel(
            p
        ),
        
        mainPanel(
            width = 9,
            h2("Link to a saved sample.html"),
            p("The url is https://johndoe.github.io/samples/sample.html"),
            a(h3("Lovely Birds"),
              href = "https://johndoe.github.io/samples/sample.html",
              target = "blank"),
            hr(),
            h2("Text and image example", id = "birds"),
            fluidRow(
                column(
                    7,
                    includeMarkdown("markdown/birds.Rmd")
                ),
                column(
                    5,
                    img(src = "birds.png", width = "100%")
                )
            ),
        )
    )
)
cannot open file 'markdown/birds.Rmd': No such file or directoryError in file(con, "r") : cannot open the connection
LS0tCnRpdGxlOiAiVmlzdWFsc19EcmFmdF8wNF8xNCIKYXV0aG9yOiAiQ29ubmllIFh1IgpkYXRlOiAiNC8xNC8yMDIxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Kc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZC9zcmMvdmlzdWFscy8iKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCnNvdXJjZSgib3VydGhlbWUuUiIpCmBgYAoKYGBge3IgcGFja2FnZXMsIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KciA9IGdldE9wdGlvbigicmVwb3MiKQpyWyJDUkFOIl0gPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIKb3B0aW9ucyhyZXBvcyA9IHIpCiMgaW5zdGFsbC5wYWNrYWdlcyAoYmFzaWMpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkcGx5cikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UpKQoKIyBpbnN0YWxsLnBhY2thZ2VzIChyZWFkaW5nKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoWE1MKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KFJDdXJsKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHJlYWRyKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KCJyZWFkeGwiKSkKCiMgaW5zdGFsbC5wYWNrYWdlcyAodGhlbWVzKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2d0aGVtZXMpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dyZXBlbCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShSQ29sb3JCcmV3ZXIpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodmlyaWRpcykpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShocmJydGhlbWVzKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHBsb3RseSkpCgoKIyBpbnN0YWxsLnBhY2thZ2VzIChtYXBzKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoUmdvb2dsZU1hcHMpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dtYXApKQpzdXBwcmVzc01lc3NhZ2VzKGluc3RhbGwucGFja2FnZXMoIm1hcHMiKSkKc3VwcHJlc3NNZXNzYWdlcyhpbnN0YWxsLnBhY2thZ2VzKCJ0bWFwIikpICMgaW5zdGFsbCB0aGUgQ1JBTiB2ZXJzaW9uCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0bWFwKSkKc3VwcHJlc3NNZXNzYWdlcyhpbnN0YWxsLnBhY2thZ2VzKCdyZ2VvcycpKQoKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGRldnRvb2xzKSkKIyBMZXQncyBpbnN0YWxsIHRoZSBkZXZlbG9wbWVudCB2ZXJzaW9uIGZyb20gR2l0aHViLiBSdW4KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyc3R1ZGlvL2xlYWZsZXQiKQpgYGAKCmBgYHtyIGltcG9ydCBnZW5lcmFsIGRhdGEsIGVjaG89VFJVRSwgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFNldCB0aGUgV0QgYXMgR3JvdXBfR19IaWdoZXJFZCAKc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZCIpCgojIFdoaWxlIG91ciBpbml0aWFsIENvbGxlZ2UgU2NvcmVjYXJkIG9ubHkgaW5jbHVkZWQgMjAxOSBpbml0aWFsbHksIEkgd2FzIGFibGUgdG8gcnVuIGEgc2ltcGxlIHB5dGhvbiBzY3JpcHQgdG8gY29uY2F0ZW5hdGUgYW5kIHNlbGVjdCBhIHNtYWxsIG51bWJlciBvZiByZWxldmFudCBjb2x1bW5zIGZvciBvdXIgdmlzdWFsaXphdGlvbiBhbmQgYW5hbHlzaXMuIFRodXMsIGFzIG91ciBmaXJzdCB2aXN1YWxpemF0aW9ucyBvbmx5IHVuY2x1ZGUgMjAxOSwgdGhlIGNvZGUgYmVsb3cgaXMgZm9yIHJlLWZpbHRlcmluZyB0aGUgY29uY2F0ZW5hdGVkIDIwMTAtMjAxOSBkYXRhIGJhY2sgaW50byBzaW1wbHkgMjAxOS4gCgpzY190aW1lIDwtIHJlYWRfY3N2KCdzcmMvMjAxMF8yMDE5X3N0dWRlbnRfZGVidC5jc3YnKSAKc2MgPC0gc2NfdGltZSAlPiUgZmlsdGVyKFllYXJfRW5kaW5nID09IDIwMTkpCgpsaWJyYXJ5KGVkdWNhdGlvbmRhdGEpCiMgVGVzdCBSdW4gd2l0aCB1c2luZyBnZXRfZWR1Y2F0aW9uX2RhdGEgCiMgZGF0YSA8LSBnZXRfZWR1Y2F0aW9uX2RhdGEobGV2ZWwgPSAiY29sbGVnZS11bml2ZXJzaXR5IiwKIyAgICAgc291cmNlID0gImlwZWRzIiwKIyAgICAgdG9waWMgPSAiZGlyZWN0b3J5IiwKIyAgICAgZmlsdGVycyA9IGxpc3QoeWVhciA9IDIwMTkpKQojIGRhdGEKIyBTY29yZWNhcmQgZGF0YSAtIDIwMTkgCgojIyBjaGFuZ2UgcHJvamVjdGlvbiBvZiBzYyBkYXRhCnNjIDwtIHNjICU+JQogIGRwbHlyOjptdXRhdGUodW5pX3JhbmsgPSBjYXNlX3doZW4oCiAgICBBRE1fUkFURSA8IDAuMiB+ICdoaWdobHkgc2VsZWN0aXZlL2VsaXRlJywKICAgIEFETV9SQVRFIDwgMC4zIH4gJ21vcmUgc2VsZWN0aXZlJywKICAgIEFETV9SQVRFIDwgMC41IH4gJ3NlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuNyB+ICdsZXNzIHNlbGVjdGl2ZScsCiAgICBUUlVFIH4gJ25vdCBzZWxlY3RpdmUnKSkgJT4lIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ25vdCBzZWxlY3RpdmUnLCAnbGVzcyBzZWxlY3RpdmUnLCAnc2VsZWN0aXZlJywgJ21vcmUgc2VsZWN0aXZlJywgJ2hpZ2hseSBzZWxlY3RpdmUvZWxpdGUnKSkpCmBgYAoKIyMgU2ltcGxlIFNjYXR0ZXJncmFtIAoKRmlyc3Qgd2UgYXJlIGdvaW5nIHRvIHRyeSB0byBwcmVzZW50IHRoaXMgcGF0dGVybiBmb3IgZGlmZmVyZW50IHRpZXJzIG9mIHVuaXZlcnNpdGllcyAoYWRtaXNzaW9uIHJhdGUgYXMgd2VsbCBhcyBkZWJ0KQpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9CiMgUmVtb3ZlIFByaXZhY3lTdXBwcmVzc2VkIFJlY29yZHMgYW5kIHRyYW5zZm9ybSBEZWJ0IE1lZGlhbiBpbnRvIGEgbnVtZXJpYyB2YWx1ZSAtIHdlIGNhbiBhbHNvIGRvIHRoaXMgb24gdGhlIG1haW4gc2MgZGYKc2MkREVCVF9NRE5baXMubmEoc2MkREVCVF9NRE4pXSA8LSAwOwoKYnJld2VyLnBhbChuPTEwLCJQdUJ1R24iKQpTaG9ydFB1QnVHbiA8LSBjKCIjRDBEMUU2IiwiI0E2QkREQiIsIiM2N0E5Q0YiLCIjMzY5MEMwIiwiIzAyODE4QSIpCgptIDwtIHNjICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICAgICAgICAgICAgICBnZ3Bsb3QoLiwgYWVzKHg9QURNX1JBVEUsIHk9REVCVF9NRE4sY29sb3I9dW5pX3JhbmspKSArCiAgZ2VvbV9wb2ludChwY2g9MjEpICsKICBnZW9tX3Ntb290aChjb2xvcj0nI0VBNEY4OCcsIHNlID0gRkFMU0UpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPVNob3J0UHVCdUduKSsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYmFja2dyb3VuZD0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIikpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1jKDAsMTAwMDAsMjAwMDAsMzAwMDApLCBsYWJlbHM9YygnMCcsJzEwJywnMjAnLCczMCcpKSArCiAgbGFicyh4PSdBZG1pc3Npb25zIFJhdGUnLCB5PSdNZWRpYW4gTG9hbiBBbW91bnQgcGVyIFN0dWRlbnRcbih0aG91c2FuZHMpJywgCiAgICAgICB0aXRsZT0nU3R1ZGVudCBEZWJ0IGFuZCBBZG1pc3Npb25zIFJhdGUnLAogICAgICAgY29sb3I9J1NlbGVjdGl2aXR5JykKbQpgYGAKClRoaXMgaXMgYSBkYXRhIHRhYmxlIHNob3dpbmcgdGhlIGJyZWFrZG93biBvZiB0aGUgdW5pdmVyc2l0eSByYW5rcyAoYXMgSSBjaG9zZSB0byByYW5rIHRoZW0pLiBJIHdpbGwgbm90ZSB0aGF0IGZyb20gdGhlIGR0IGFsb25lIHd3ZSBhcmUgc2VlaW5nIGEgZG93bndhcmQgdHJlbmQgaW4gdGhlICdNZWRpYW4gU3R1ZGVudCBMb2FucycgY29sdW1uLiAKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojIENyZWF0ZSBEYXRhIFRhYmxlIChTdW1tYXJpemVkKSBmb3IgCmxpYnJhcnkoJ3NjYWxlcycpCgpzY19kdCA8LSBzYyAlPiUgc3Vic2V0KERFQlRfTUROICE9J1ByaXZhY3lTdXBwcmVzc2VkJykgJT4lIHRyYW5zZm9ybShERUJUX01ETiA9IGFzLm51bWVyaWMoREVCVF9NRE4pKSAlPiUgZ3JvdXBfYnkodW5pX3JhbmspICU+JSBtdXRhdGUoYE51bWJlciBvZiBVbml2ZXJzaXRpZXNgID0gbigpKSAlPiUgdW5ncm91cCgpICU+JSBtdXRhdGUoREVCVF9NRE5fU1RVREVOVFMgPSBERUJUX01ETipVR0RTKSAlPiUgZ3JvdXBfYnkodW5pX3JhbmspICU+JSBtdXRhdGUoYE1lZGlhbiBTdHVkZW50IExvYW5zYCA9IHBhc3RlKCckJyxyb3VuZChzdW0oREVCVF9NRE5fU1RVREVOVFMsIG5hLnJtPVRSVUUpL3N1bShVR0RTLCBuYS5ybT1UUlVFKSwyKSkpICU+JSAKICBtdXRhdGUoYE1pbiBBY2NlcHRhbmNlIFJhdGVgID0gcGVyY2VudChtaW4oQURNX1JBVEUpKSkgJT4lIG11dGF0ZShgTWF4IEFjY2VwdGFuY2UgUmF0ZWAgPSBwZXJjZW50KG1heChBRE1fUkFURSkpKSAlPiUgdW5ncm91cCgpICU+JSAKICBncm91cF9ieSh1bmlfcmFuayxgTWVkaWFuIFN0dWRlbnQgTG9hbnNgLGBOdW1iZXIgb2YgVW5pdmVyc2l0aWVzYCxgTWluIEFjY2VwdGFuY2UgUmF0ZWAsYE1heCBBY2NlcHRhbmNlIFJhdGVgKSAlPiUgCiAgc3VtbWFyaXplKCkKCmluc3RhbGwucGFja2FnZXMoJ0RUJykKbGlicmFyeShEVCkKdGFibGUgPC0gZGF0YXRhYmxlKHNjX2R0LHN0eWxlID0gImRlZmF1bHQiLGZpbHRlciA9ICd0b3AnLCAgY2FwdGlvbiA9ICdVbml2ZXJzaXRpZXMgYW5kIFNlbGVjdGl2aXR5JykKdGFibGUKCmBgYAoKIyMgU2NhdHRlcmdyYW0gYXMgVmlvbGluIFBsb3QKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQptIDwtIHNjICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKHg9dW5pX3JhbmssIHk9REVCVF9NRE4pKSArCiAgZ2VvbV92aW9saW4oYWVzKGZpbGw9dW5pX3JhbmssY29sb3I9dW5pX3JhbmspKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9U2hvcnRQdUJ1R24pICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1TaG9ydFB1QnVHbikgKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiKSkrCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHM9YygwLDEwMDAwLDIwMDAwLDMwMDAwKSwgbGFiZWxzPWMoJzAnLCcxMCcsJzIwJywnMzAnKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoJ25vdFxuc2VsZWN0aXZlXG4oPjcwJSknLCdsZXNzXG5zZWxlY3RpdmVcbig1MCUtNzAlKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc2VsZWN0aXZlXG4oMzAlLTUwJSknLCdtb3JlXG5zZWxlY3RpdmVcbigyMCUtMzAlKScsJ2hpZ2hseVxuc2VsZWN0aXZlXG4oNSUtMjAlKScsJ2VsaXRlXG4oPDUlKScpKSArCgogIGxhYnMoeD0nU2VsZWN0aXZpdHlcbihhZG1pc3Npb24gcmF0ZSB0aHJlc2hvbGRzKScsIHk9J01lZGlhbiBMb2FuIEFtb3VudCBwZXIgU3R1ZGVudFxuKHRob3VzYW5kcyknLCAKICAgICAgIHRpdGxlPSdTZWxlY3RpdmUgU2Nob29scyBhbmQgU3R1ZGVudCBEZWJ0JywKICAgICAgIGNvbG9yPScnLGZpbGw9JycpCm0KYGBgClNob3dpbmcgdGhlIHByZXZpb3VzIHNjYXR0ZXJncmFtIHNwZWNpZmljYWxseSBhcyB2aW9saW5nIHBsb3RzCgpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9CmlwZWRzMTUgPC0gZ2V0X2VkdWNhdGlvbl9kYXRhKGxldmVsID0gImNvbGxlZ2UtdW5pdmVyc2l0eSIsCiAgICBzb3VyY2UgPSAiaXBlZHMiLAogICAgdG9waWMgPSAiZ3JhZC1yYXRlcy1wZWxsIiwKICAgIGZpbHRlcnMgPSBsaXN0KHllYXIgPSAyMDE1KSkKaXBlZHMxNQpgYGAKCgojIyBTdHVkZW50IERlYnQgb3ZlciBUaW1lCgpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9CgojUHJvY2VzcyB0aGUgZGF0YSAKc2NfdGltZSA8LSByZWFkX2NzdignMjAxMF8yMDE5X3N0dWRlbnRfZGVidC5jc3YnKSAKCnNjX3RpbWU8LSBzY190aW1lICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKQoKYGBgCgoKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojUHJvY2VzcyB0aGUgZGF0YSAKc2NfdGltZSA8LSByZWFkX2NzdignMjAwOV8yMDE5X3N0dWRlbnRfZGVidC5jc3YnKSAKCnNjX3RpbWU8LSBzY190aW1lICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKSAlPiUgCiAgbXV0YXRlKERFQlRfTUROX1NUVURFTlQgPSBERUJUX01ETipVR0RTKQpzY190aW1lCgpzdW0oc2NfdGltZSRVR0RTLG5hLnJtPVRSVUUpCmBgYAoKQmVsb3cgaXMgYW4gaW50ZXJhY3RpdmUgbGluZSBncmFwaCAoMjAxMC0yMDE5KSB3aGljaCBkZXRhaWxzIHRoZSB0cmVuZHMgaW4gc3R1ZGVudCBkZWJ0IG92ZXIgdGhlIHllYXJzLiAKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojIENQSSBJbmZsYXRpb24gUmF0ZXMgLSBHb3QgQXZlcmFnZSBZZWFybHkgSW5mbGF0aW9uIFJhdGUgZm9yIFNjYWxpbmcgZm9yIFN0dWRlbnQgRGVidCAKaW5zdGFsbC5wYWNrYWdlcygncXVhbnRtb2QnKQpsaWJyYXJ5KHF1YW50bW9kKQpnZXRTeW1ib2xzKCJDUElBVUNTTCIsIHNyYz0nRlJFRCcpCmF2Zy5jcGkgPC0gYXBwbHkueWVhcmx5KENQSUFVQ1NMLCBtZWFuKQpjZiA8LSBhcy5kYXRhLmZyYW1lKGF2Zy5jcGkvYXMubnVtZXJpYyhhdmcuY3BpWycyMDA5J10pKSAKY2YkWWVhcl9FbmRpbmcgPC0gZm9ybWF0KGFzLkRhdGUocm93Lm5hbWVzKGNmKSwgZm9ybWF0PSIlWS0lbS0lZCIpLCIlWSIpCgojIE1lcmdlZCBmb3IgSW5mbGF0aW9uIApzY190aW1lX2RmIDwtIHNjX3RpbWUgJT4lIGdyb3VwX2J5KGBZZWFyX0VuZGluZ2ApICU+JSBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgdW5ncm91cCgpICU+JSAKICBkcGx5cjo6bXV0YXRlKHVuaV9yYW5rID0gY2FzZV93aGVuKAogICAgQURNX1JBVEUgPCAwLjIgfiAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuMyB+ICdtb3JlIHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuNSB+ICdzZWxlY3RpdmUnLAogICAgQURNX1JBVEUgPCAwLjcgfiAnbGVzcyBzZWxlY3RpdmUnLAogICAgVFJVRSB+ICdub3Qgc2VsZWN0aXZlJykpICU+JQogIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ25vdCBzZWxlY3RpdmUnLCAnbGVzcyBzZWxlY3RpdmUnLCAnc2VsZWN0aXZlJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbW9yZSBzZWxlY3RpdmUnLCAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lCiAgZ3JvdXBfYnkodW5pX3JhbmssWWVhcl9FbmRpbmcpICU+JSAKICBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShgWWVhcl9FbmRpbmdgLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsCiAgICAgICAgICAgdW5pX3JhbmssYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIHN1bW1hcml6ZSgpICU+JSAKICBtZXJnZShjZikgJT4lIAogIG11dGF0ZShgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCA9IGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAvCiAgICAgICAgICAgQ1BJQVVDU0wpICU+JSAKICBtdXRhdGUoYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWAgPSBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLwogICAgICAgICAgIENQSUFVQ1NMKQoKc2NfZGYgPC0gc2NfdGltZV9kZiAlPiUgZ3JvdXBfYnkoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCxgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCxZZWFyX0VuZGluZykgJT4lIHN1bW1hcml6ZSgpICU+JSBtdXRhdGUodW5pX3Jhbms9J25hdGlvbmFsIGF2ZXJhZ2UnKSAlPiUgbXV0YXRlKGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgPWBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgKSAlPiUgZHBseXI6Om11dGF0ZShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgID0gYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIG1lcmdlKGNmKSAlPiUgc2VsZWN0KFllYXJfRW5kaW5nLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsIHVuaV9yYW5rLCBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLCBDUElBVUNTTCwgYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGAsYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWApCnNjX3RpbWVfZGYgPC0gc2NfdGltZV9kZiAlPiUgcmJpbmQoc2NfZGYpICU+JSBtdXRhdGUodW5pX3JhbmsgPSBmYWN0b3IodW5pX3JhbmssIGxldmVscz1jKCduYXRpb25hbCBhdmVyYWdlJywnbm90IHNlbGVjdGl2ZScsICdsZXNzIHNlbGVjdGl2ZScsICdzZWxlY3RpdmUnLCAnbW9yZSBzZWxlY3RpdmUnLCAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lIAogIG11dGF0ZShuYXRpb25hbCA9IGlmZWxzZSh1bmlfcmFuayA9PSAnbmF0aW9uYWwgYXZlcmFnZScsICd5JywnbicpKQpzY19kZgpzY190aW1lX2RmCgoKcCA8LSBzY190aW1lX2RmICU+JSAKICBnZ3Bsb3QoLixhZXMoeD1ZZWFyX0VuZGluZyx5PWBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgLCBjb2xvcj11bmlfcmFuaywgZ3JvdXA9bmF0aW9uYWwpKSArIAogIGdlb21fcG9pbnQoKSArIGdlb21fbGluZShhZXMobGluZXR5cGU9bmF0aW9uYWwpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnZ3JleScsIiNEMEQxRTYiLCIjQTZCRERCIiwiIzY3QTlDRiIsIiMzNjkwQzAiLCIjMDI4MThBIikpKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEobWluKHNjX3RpbWUkWWVhcl9FbmRpbmcpLCBtYXgoc2NfdGltZSRZZWFyX0VuZGluZyksIGJ5ID0gMiksMSkpICsKICBsYWJzKHg9JycsIHk9J01lZGlhbiBMb2FuIEFtb3VudCBwZXIgU3R1ZGVudFxuKHRob3VzYW5kcykqKicsIAogICAgICAgdGl0bGU9J1N0dWRlbnQgRGVidCBIYXMgQmVlbiBSaXNpbmcgT3ZlciBUaGUgWWVhcnMnLAogICAgICAgY29sb3I9JycsZmlsbD0nJywgY2FwdGlvbj0nKiotaW5mbGF0aW9uIGFkanVzdGVkJykKZ2dwbG90bHkocCkKCgpgYGAKClRoZSBmb2xsb3dpbmcgaXMgKGluc3RlYWQpIGEgYmFyIGdyYXBoIHdpdGggZmV3ZXIgJ3VuaXZlcnNpdHkgc2VsZWN0aXZpdHknIGJ1Y2tldHMuIApgYGB7cn0Kc2NfdGltZV9kZiA8LSBzY190aW1lICU+JSBncm91cF9ieShgWWVhcl9FbmRpbmdgKSAlPiUgbXV0YXRlKGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBOYXRpb25hbGAgPSBzdW0oREVCVF9NRE5fU1RVREVOVCxuYS5ybT1UUlVFKS9zdW0oVUdEUyxuYS5ybT1UUlVFKSkgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgZHBseXI6Om11dGF0ZSh1bmlfcmFuayA9IGNhc2Vfd2hlbigKICAgIEFETV9SQVRFIDwgMC4yIH4gJ2hpZ2hseSBzZWxlY3RpdmUnLAogICAgQURNX1JBVEUgPCAwLjUgfiAnbW9kZXJhdGVseSBzZWxlY3RpdmUnLAogICAgVFJVRSB+ICdsZXNzL25vdCBhdCBhbGwgc2VsZWN0aXZlJykpICU+JQogIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ2xlc3Mvbm90IGF0IGFsbCBzZWxlY3RpdmUnLCAnbW9kZXJhdGVseSBzZWxlY3RpdmUnLCAnaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lCiAgZ3JvdXBfYnkodW5pX3JhbmssWWVhcl9FbmRpbmcpICU+JSAKICBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShgWWVhcl9FbmRpbmdgLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsCiAgICAgICAgICAgdW5pX3JhbmssYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIHN1bW1hcml6ZSgpICU+JSAKICBtZXJnZShjZikgJT4lIAogIG11dGF0ZShgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCA9IGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAvCiAgICAgICAgICAgQ1BJQVVDU0wpICU+JSAKICBtdXRhdGUoYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWAgPSBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLwogICAgICAgICAgIENQSUFVQ1NMKQoKc2NfZGYgPC0gc2NfdGltZV9kZiAlPiUgZ3JvdXBfYnkoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCxgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCxZZWFyX0VuZGluZykgJT4lIHN1bW1hcml6ZSgpICU+JSBtdXRhdGUodW5pX3Jhbms9J25hdGlvbmFsIGF2ZXJhZ2UnKSAlPiUgbXV0YXRlKGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgPWBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgKSAlPiUgZHBseXI6Om11dGF0ZShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgID0gYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIG1lcmdlKGNmKSAlPiUgc2VsZWN0KFllYXJfRW5kaW5nLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsIHVuaV9yYW5rLCBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLCBDUElBVUNTTCwgYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGAsYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWApCnNjX3RpbWVfZGYgPC0gc2NfdGltZV9kZiAlPiUgcmJpbmQoc2NfZGYpICU+JSBtdXRhdGUodW5pX3JhbmsgPSBmYWN0b3IodW5pX3JhbmssIGxldmVscz1jKCduYXRpb25hbCBhdmVyYWdlJywnbGVzcy9ub3QgYXQgYWxsIHNlbGVjdGl2ZScsICdtb2RlcmF0ZWx5IHNlbGVjdGl2ZScsICdoaWdobHkgc2VsZWN0aXZlJykpKSAKCmZpZzEgPC0gc2NfdGltZV9kZiAlPiUgcGxvdF9seSh4ID0gflllYXJfRW5kaW5nLCB5ID0gfmBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgLCB0eXBlID0gJ2JhcicsCiAgY29sb3IgPSB+dW5pX3JhbmssIGFscGhhPTAuOCwgaG92ZXJ0ZW1wbGF0ZSA9ICdBdmVyYWdlIERlYnQvU3R1ZGVudCAoVVNEKTogJXt5fSA8ZXh0cmE+PC9leHRyYT4nLGNvbG9ycz0nUHVycGxlcycpICU+JSAKICBsYXlvdXQoeWF4aXMgPSBsaXN0KAogIHRpdGxlID0gIkF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCBwZXIgU3R1ZGVudFxuKEFkanVzdGVkIGZvciBJbmZsYXRpb24pIikpCgpmaWcxCgpgYGAKCkNobG9yb3BsZXRoIHNob3dpbmcgYXZlcmFnZSBzdHVkZW50IGRlYnQgKHRoaXMgaXMgb25seSAyMDE5IGJ1dCBJIGhhdmUgYSBmaWx0ZXIgYXQgdGhlIGJlZ2lubmluZyB0aGF0IHdpbGwgYWxsb3cgbWUgdG8gaW5jb3Jwb3JhdGUgYSBzbGlkZXIgZm9yIHRoZSB5ZWFyKS4KCmBgYHtyIFN0dWRlbnQgRGVidCBtYXAgLSBDaGxvcm9wbGV0aCwgZWNobz1UUlVFLCBldmFsPVRSVUUgfQojIEFkZGl0aW9ucyBvZiBTdGF0ZXMgZGYgZnJvbSBUaWdyaXMgRmlsZSAKbGlicmFyeSh0aWdyaXMpCnN0YXRlcyA8LSBzdGF0ZXMoY2IgPSBUUlVFKQoKIyBDYW4gY2hhbmdlIHRvIHNjX3RpbWVfeWVhciAKc2NfdGltZV8yMDE5IDwtIHNjX3RpbWUgJT4lIHN1YnNldChZZWFyX0VuZGluZyA9IDIwMTkpICU+JSAKICBncm91cF9ieShTVEFCQlIpICU+JSBtdXRhdGUoYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2A9c3VtKERFQlRfTUROX1NUVURFTlQsbmEucm09VFJVRSkvc3VtKFVHRFMsbmEucm09VFJVRSkpCnNjX3RpbWVfMjAxOV9zdGF0ZSA8LSBzY190aW1lXzIwMTkgJT4lIGdyb3VwX2J5KFNUQUJCUixgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkgJT4lIHN1bW1hcml6ZSgpCgojIFN0YXRlcyAKc3RhdGVzXzIwMTkgPC0gc3RhdGVzICU+JSAKICBpbm5lcl9qb2luKHNjX3RpbWVfMjAxOV9zdGF0ZSwgYnk9YyhTVFVTUFM9J1NUQUJCUicpKSAKCgpsaWJyYXJ5KGxlYWZsZXQucHJvdmlkZXJzKQpsaWJyYXJ5KGxlYWZsZXQpCiN1c2VkICdzdWNjZXNzJyBtZWFzdXJlcy4gCgpwYWwgPSBjb2xvckZhY3RvcihTaG9ydFB1QnVHbiwgZG9tYWluID0gc3RhdGVzXzIwMTkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApCnN0YXRlc18yMDE5CnBvcF9wb3AgPC0gcGFzdGUoIlN0YXRlOiIsc3RhdGVzXzIwMTkkTkFNRSwiPGJyLz4iLAogICAgICAgICAgICAgICAgICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMiLCI8YnIvPiIsCiAgICAgICAgICAgICAgICAgIm9mIFNjaG9vbHMgTG9jYXRlZCBpbiBTdGF0ZToiLHBhc3RlKCckJyxyb3VuZChzdGF0ZXNfMjAxOSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkpKQoKbGVhZmxldChzdGF0ZXNfMjAxOSkgJT4lIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKHN0YXRlc18yMDE5JGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSwKICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMC41LAogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LCAgCiAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygKICAgICAgICAgICAgICAgIHdlaWdodCA9IDUsCiAgICAgICAgICAgICAgICBjb2xvciA9ICIjNjY2IiwKICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LAogICAgICAgICAgICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSwKICAgICAgICAgICAgICAgICkscG9wdXA9cG9wX3BvcCkgJT4lCiAgbGVhZmxldDo6YWRkTGVnZW5kKHBvc2l0aW9uID0gImJvdHRvbWxlZnQiLCBwYWwgPSBwYWwsIHZhbHVlcyA9IGMocGFzdGUoJyQnLHJvdW5kKG1pbihzdGF0ZXNfMjAxOSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgnJCcscm91bmQobWF4KHN0YXRlc18yMDE5JGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSkpKSwKICAgICAgICAgICAgdGl0bGUgPSAiQXZlcmFnZSBTdHVkZW50IExvYW5zIChQZXIgU3R1ZGVudCkiKSAlPiUgICBzZXRWaWV3KC05OC41Nzk1LCAzOS44MjgyLCB6b29tPTMpCj9hZGRMZWdlbmQKYGBgCgpgYGB7cn0KYnJld2VyLnBhbChuID0gOCwgbmFtZSA9ICJSZFlsR24iKQpgYGAKCmBgYHtyIFN0dWRlbnQgRGVidCBNYXAgLSBwb2ludHMsIGVjaG89VFJVRSwgZXZhbD1UUlVFIH0KIyBsYXN0IGVkaXQgdG8gc2NfdGltZV8yMDE5IGluIGNodW5rIGFib3ZlIGZvciBjaGxvcm9wbGV0aApzY190aW1lXzIwMTlfc2VsZWN0aXZlIDwtIHNjX3RpbWVfMjAxOSAlPiUgZHBseXI6OnJlbmFtZShsYXQgPSBMQVRJVFVERSkgJT4lIGRwbHlyOjpyZW5hbWUobG9uZyA9IExPTkdJVFVERSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoc3RhdGUgPSBTVEFCQlIpICU+JSBmaWx0ZXIoQURNX1JBVEUgPCAwLjMpICU+JSAKICBkcGx5cjo6bXV0YXRlKHVuaV9yYW5rID0gY2FzZV93aGVuKAogICAgQURNX1JBVEUgPCAwLjA1IH4gJ2VsaXRlJywKICAgIEFETV9SQVRFIDwgMC4yIH4gJ2hpZ2hseSBzZWxlY3RpdmUnLAogICAgVFJVRSB+ICdzZWxlY3RpdmUnKSkKc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSA8LSBzY190aW1lXzIwMTlfc2VsZWN0aXZlICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKSAKCgoKcGFsMSA9IGNvbG9yRmFjdG9yKFNob3J0UHVCdUduLCBkb21haW4gPSBzY190aW1lXzIwMTlfc2VsZWN0aXZlJGB1bmlfcmFua2AscmV2ZXJzZT1UUlVFKQoKI3NldCBwb3B1cHMgCmNvbnRlbnQgPC0gcGFzdGUoIlNjaG9vbCIsc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSRJTlNUTk0sIjxici8+IiwKICAgICAgICAgICAgICAgICAiTnVtYmVyIG9mIFVuZGVyZ3JhZHM6IixzY190aW1lXzIwMTlfc2VsZWN0aXZlJFVHRFMsIjxici8+IiwKICAgICAgICAgICAgICAgICAiU2VsZWN0aXZpdHk6Iiwgc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSR1bmlfcmFuaywiPGJyLz4iLAogICAgICAgICAgICAgICAgICJNZWRpYW4gRGVidDoiLHBhc3RlKCckJyxyb3VuZChzY190aW1lXzIwMTlfc2VsZWN0aXZlJERFQlRfTUROLDIpKSwiPGJyLz4iKQpzY190aW1lXzIwMTlfc2VsZWN0aXZlCmxlYWZsZXQoc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSkgJT4lIGFkZFRpbGVzKCdodHRwOi8ve3N9LmJhc2VtYXBzLmNhcnRvY2RuLmNvbS9kYXJrX2FsbC97en0ve3h9L3t5fS5wbmcnKSAlPiUKICBhZGRDaXJjbGVzKGNvbCA9IH5wYWwxKHNjX3RpbWVfMjAxOV9zZWxlY3RpdmUkdW5pX3JhbmspLAogICAgICAgICAgICAgcmFkaXVzID0gfkRFQlRfTUROLAogICAgICAgICAgICAgcG9wdXAgPSBjb250ZW50LAogICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjcpICU+JQogIGxlYWZsZXQ6OmFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21sZWZ0IixwYWwgPSBwYWwxLCB2YWx1ZXMgPSBzY190aW1lXzIwMTlfc2VsZWN0aXZlJHVuaV9yYW5rLAogICAgICAgICAgICB0aXRsZSA9ICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMgKFBlciBTdHVkZW50KSIpCj9hZGRMZWdlbmQKYGBgCgoKVGhlIGNvZGUgY2h1bmsgYmVsb3cgaGFzIG5vdCBiZWVuIHRvdWNoZWQgYW5kIGluY2x1ZGVzIFNoaW55IGNvZGUgZm9yIGxhdGVyIHVzZS4gCmBgYHtyfQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHNoaW55KQp1aSA8LSBmbHVpZFBhZ2UoCiAgICBzaWRlYmFyTGF5b3V0KAogICAgICAgIHNpZGViYXJQYW5lbCgKICAgICAgICAgICAgcAogICAgICAgICksCiAgICAgICAgCiAgICAgICAgbWFpblBhbmVsKAogICAgICAgICAgICB3aWR0aCA9IDksCiAgICAgICAgICAgIGgyKCJMaW5rIHRvIGEgc2F2ZWQgc2FtcGxlLmh0bWwiKSwKICAgICAgICAgICAgcCgiVGhlIHVybCBpcyBodHRwczovL2pvaG5kb2UuZ2l0aHViLmlvL3NhbXBsZXMvc2FtcGxlLmh0bWwiKSwKICAgICAgICAgICAgYShoMygiTG92ZWx5IEJpcmRzIiksCiAgICAgICAgICAgICAgaHJlZiA9ICJodHRwczovL2pvaG5kb2UuZ2l0aHViLmlvL3NhbXBsZXMvc2FtcGxlLmh0bWwiLAogICAgICAgICAgICAgIHRhcmdldCA9ICJibGFuayIpLAogICAgICAgICAgICBocigpLAogICAgICAgICAgICBoMigiVGV4dCBhbmQgaW1hZ2UgZXhhbXBsZSIsIGlkID0gImJpcmRzIiksCiAgICAgICAgICAgIGZsdWlkUm93KAogICAgICAgICAgICAgICAgY29sdW1uKAogICAgICAgICAgICAgICAgICAgIDcsCiAgICAgICAgICAgICAgICAgICAgaW5jbHVkZU1hcmtkb3duKCJtYXJrZG93bi9iaXJkcy5SbWQiKQogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIGNvbHVtbigKICAgICAgICAgICAgICAgICAgICA1LAogICAgICAgICAgICAgICAgICAgIGltZyhzcmMgPSAiYmlyZHMucG5nIiwgd2lkdGggPSAiMTAwJSIpCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICksCiAgICAgICAgKQogICAgKQopCgoKYGBgCgoKCg==